/*
 * libSockets.c
 *
 *  Created on: 30/11/2011
 *      Author: utn_so
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>

#include "libSockets.h"
#include "tiposSockets.h"
#include "libPaquetes.h"
#include "tiposPaquetes.h"

extern char IP_ACTIVA[NI_MAXHOST];
extern char PUERTO_ACTIVO[10];
extern char IP_DISCO[NI_MAXHOST];
extern char PUERTO_DISCO[10];
extern char IP_RAID1[NI_MAXHOST];
extern char PUERTO_RAID1[10];
extern int32_t MAX_CONEXIONES;
extern t_conexion* poolConexiones;

extern pthread_mutex_t mutexUsandoPoolConexiones;
extern sem_t semConexiones;

extern int8_t imprimirDebug;
extern int8_t usarPoolConexiones;

extern int32_t errno;

int8_t estaEnUso(int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------estaEnUso--------------------\n");
	}
	uint8_t i;
	for (i = 0; i < MAX_CONEXIONES && poolConexiones[i].descriptor != descriptor; i++)
		;
	if (i < MAX_CONEXIONES && poolConexiones[i].descriptor == descriptor) {
		if (imprimirDebug) {
			printf("--------------------fin-estaEnUso--------------------\n");
		}
		return poolConexiones[i].enUso;
	} else {
		if (imprimirDebug) {
			printf("--------------------fin-estaEnUso--------------------\n");
		}
	}
	return -1;
}

int8_t cerrarConexion(int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------cerrarConexion--------------------\n");
	}
	if (imprimirDebug) {
		/**/printf("Voy a cerrar el descriptor [%d].\n", descriptor);
	}

	if (usarPoolConexiones) {
		uint8_t i;
		for (i = 0; i < MAX_CONEXIONES && poolConexiones[i].descriptor != descriptor; i++) {
			if (poolConexiones[i].descriptor == descriptor) {
				if (imprimirDebug) {
					/**/printf("Encontre el descriptor.\n");
				}
			} else {
				if (imprimirDebug) {
					/**/printf("En el lugar [%d] esta el descriptor [%d].\n", i, poolConexiones[i].descriptor);
				}
			}
		}
		if (i < MAX_CONEXIONES && poolConexiones[i].descriptor == descriptor) {
			if (imprimirDebug) {
				/**/printf("Cierro el descriptor [%d].\n", descriptor);
			}
			close(poolConexiones[i].descriptor);
			poolConexiones[i].enUso = -1;
		}
	} else {
		int32_t resClose = close(descriptor);
		if (resClose != -1) {
			sem_post(&semConexiones);
		}
	}
	if (imprimirDebug) {
		printf("--------------------fin-cerrarConexion--------------------\n");
	}
	return 0;
}

int8_t obtenerConexion(int32_t* descriptor) {
	if (imprimirDebug) {
		printf("--------------------obtenerConexion--------------------\n");
	}
	if (usarPoolConexiones) {
		uint8_t i;
		int8_t encontrada = 0;
		while (!encontrada) {
			pthread_mutex_lock(&mutexUsandoPoolConexiones);
			if (imprimirDebug) {
				printf("Buscando una Conexion.\n");
			}
			for (i = 0; i < MAX_CONEXIONES && poolConexiones[i].enUso == 1; i++)
				;

			if (i < MAX_CONEXIONES && poolConexiones[i].enUso == -1) {
				if (imprimirDebug) {
					printf("La conexion [%d] no fue utilizada.\n", i);
				}
				*descriptor = (int32_t) socket(AF_INET, SOCK_STREAM, 0);

				struct sockaddr_in *local_address = malloc(sizeof(struct sockaddr_in));
				struct sockaddr_in *remote_address = malloc(sizeof(struct sockaddr_in));

				{
					local_address->sin_family = AF_INET;
					local_address->sin_addr.s_addr = INADDR_ANY;
					local_address->sin_port = htons(MI_PUERTO + i);

				}

				//uint32_t optval;
				//optval = 1;
				//setsockopt(*descriptor, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
				if (imprimirDebug) {
					/**/printf("Quiero bindear con el puerto [%d].\n", MI_PUERTO + i);
				}
				int32_t resBind = 1; //bind(*descriptor, (struct sockaddr*) local_address, sizeof(struct sockaddr_in));

				if (imprimirDebug) {
					/**/printf("Resultado del bindeo: [%d].\n", resBind);
				}
				if (resBind != -1) {
					if (imprimirDebug) {
						printf("Bindie con mi puerto : [%d].\n", MI_PUERTO + i);
					}

					{
						remote_address->sin_family = AF_INET;
						remote_address->sin_addr.s_addr = inet_addr(IP_ACTIVA);
						remote_address->sin_port = (uint16_t) htons(atoi(PUERTO_ACTIVO));
					}

					if (imprimirDebug) {
						printf("Trato de conectarme al IP: [%s], Puerto: [%s]\n", IP_ACTIVA, PUERTO_ACTIVO);
					}
					int8_t resCon;
					resCon = (int8_t) connect(*descriptor, (struct sockaddr*) remote_address, sizeof(struct sockaddr_in));

					if (resCon != -1) {
						poolConexiones[i].enUso = 1;
						poolConexiones[i].descriptor = *descriptor;
						if (imprimirDebug) {
							printf("Le asigno a la conexion [%d] el descriptor [%d].\n", i, poolConexiones[i].descriptor);
						}
						int8_t resHS = hacerHandShake(*descriptor);
						if (resHS != -1) {
							encontrada = 1;
						} else {
							encontrada = 0;
							poolConexiones[i].enUso = -1;
						}
					} else {
						if (imprimirDebug) {
							printf("Hubo un error en la conexion.\n");
						}
						close(*descriptor);
						encontrada = 0;
					}
				} else {
					if (imprimirDebug) {
						printf("Hubo un error en el bindeo.\n");
					}
					close(*descriptor);
					encontrada = 0;
				}

			} else if (i < MAX_CONEXIONES && poolConexiones[i].enUso == 0) {
				if (imprimirDebug) {
					printf("La conexion [%d] con el descriptor [%d] esta disponible.\n", i, poolConexiones[i].descriptor);
				}
				poolConexiones[i].enUso = 1;
				*descriptor = poolConexiones[i].descriptor;
				encontrada = 1;
			}
			pthread_mutex_unlock(&mutexUsandoPoolConexiones);
		}
		if (imprimirDebug) {
			printf("--------------------fin-obtenerConexion--------------------\n");
		}
	} else {
		int8_t encontrada = 0;
		while (!encontrada) {
			sem_wait(&semConexiones);
			*descriptor = (int32_t) socket(AF_INET, SOCK_STREAM, 0);
			struct sockaddr_in *remote_address = malloc(sizeof(struct sockaddr_in));
			{
				remote_address->sin_family = AF_INET;
				remote_address->sin_addr.s_addr = inet_addr(IP_ACTIVA);
				remote_address->sin_port = (uint16_t) htons(atoi(PUERTO_ACTIVO));
			}
			int8_t resCon = (int8_t) connect(*descriptor, (struct sockaddr*) remote_address, sizeof(struct sockaddr_in));

			if (resCon != 0) {
				perror("connect()");
			} else {
				int8_t resHS = hacerHandShake(*descriptor);
				if (resHS == -1) {
					int32_t resClose = close(*descriptor);
					if (resClose != -1) {
						sem_post(&semConexiones);
					}
					encontrada = 0;
				} else {
					encontrada = 1;
				}
			}
		}
	}
	return 0;
}

int8_t habilitarConexion(int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------habilitarConexion--------------------\n");
	}
	uint8_t i;
	for (i = 0; i < MAX_CONEXIONES && poolConexiones[i].descriptor != descriptor; i++)
		;
	if (i < MAX_CONEXIONES && poolConexiones[i].descriptor == descriptor) {
		poolConexiones[i].enUso = 0;
	}
	if (imprimirDebug) {
		printf("--------------------fin-habilitarConexion--------------------\n");
	}
	return 0;
}

int8_t enviarPaquete(t_paquete paquete, int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------enviarPaquete--------------------\n");
	}
	int32_t bytesEnviados;
	int8_t error = 0;

	if (estaEnUso(descriptor)) {
		char* envio;
		error = desempaquetar(paquete, &envio);
		if (imprimirDebug) {
			printf("desempaquete\n");
		}
		if (!error) {
			if (imprimirDebug) {
				printf("[%d][%d][%d]\n", envio[0], envio[1], envio[2]);
			}

			bytesEnviados = send(descriptor, envio, paquete.pLength + 3, 0);
			if (bytesEnviados != -1) {
				if (imprimirDebug) {
					printf("envie: [%d][%d][%d]\n", envio[0], envio[1], envio[2]);
				}
				error = 0;
			} else {
				//ERROR DE ENVIO
				pthread_mutex_lock(&mutexUsandoPoolConexiones);
				habilitarConexion(descriptor);
				pthread_mutex_unlock(&mutexUsandoPoolConexiones);
				error = 2;
			}
		}
		free(envio);
	} else
		//EL DESCRIPTOR NO ESTA OCUPADO, NO LO PUEDO USAR
		error = 1;
	if (imprimirDebug) {
		printf("--------------------fin-enviarPaquete--------------------\n");
	}
	return error;
}

int8_t recibirPaquete(t_paquete* paquete, int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------recibirPaquete--------------------\n");
	}
	int8_t error = 0;
	if (estaEnUso(descriptor)) {
		char buffer[MAX_BUFFER];
		memset(buffer, '\0', MAX_BUFFER);
		if (imprimirDebug) {
			printf("Descriptor: [%d].\n", descriptor);
		}
		int32_t resRecv = recv(descriptor, buffer, MAX_BUFFER, 0);
		if (resRecv != -1) {
			if (imprimirDebug) {
				printf("Recibi [%d].\n", resRecv);
			}
			if (imprimirDebug) {
				printf("Contenido: [%d][%d][%d] = [%s].\n", buffer[0], buffer[1], buffer[2], buffer);
			}
			error = empaquetar(buffer, paquete);
			if (imprimirDebug) {
				printf("Recibi [%d][%d].\n", paquete->type, paquete->pLength);
			}
		} else {
			//ERROR AL RECIBIR
			if (imprimirDebug) {
				printf("Error en el recv.\n");
			}
			/*pthread_mutex_lock(&mutexUsandoPoolConexiones);
			 habilitarConexion(descriptor);
			 pthread_mutex_unlock(&mutexUsandoPoolConexiones);*/
			error = 2;
		}
	} else
		//EL DESCRIPTOR NO ESTA OCUPADO, NO LO PUEDO USAR
		error = 1;
	if (imprimirDebug) {
		printf("--------------------fin-recibirPaquete--------------------\n");
	}
	return error;
}

int8_t cerrarTodasLasConexiones() {
	if (imprimirDebug) {
		printf("--------------------cerrarTodasLasConexiones--------------------\n");
	}
	uint8_t i;
	for (i = 0; i < MAX_CONEXIONES; i++) {
		if (poolConexiones[i].enUso != -1) {
			close(poolConexiones[i].descriptor);
			poolConexiones[i].descriptor = 0;
			poolConexiones[i].enUso = -1;
		}
	}
	if (imprimirDebug) {
		printf("--------------------fin-cerrarTodasLasConexiones--------------------\n");
	}
	return 0;
}

int8_t cambiarConexionActivaARaid1() {
	if (imprimirDebug) {
		printf("--------------------cambiarConexionActivaARaid1--------------------\n");
	}
	if (usarPoolConexiones) {
		cerrarTodasLasConexiones();
		memset(IP_ACTIVA, '\0', NI_MAXHOST);
		memcpy(IP_ACTIVA, IP_RAID1, NI_MAXHOST);
		memset(PUERTO_ACTIVO, '\0', 10);
		memcpy(PUERTO_ACTIVO, PUERTO_RAID1, 10);
	} else {
		memset(IP_ACTIVA, '\0', NI_MAXHOST);
		memcpy(IP_ACTIVA, IP_RAID1, NI_MAXHOST);
		memset(PUERTO_ACTIVO, '\0', 10);
		memcpy(PUERTO_ACTIVO, PUERTO_RAID1, 10);
	}
	if (imprimirDebug) {
		printf("--------------------fin-cambiarConexionActivaARaid1--------------------\n");
	}
	return 0;
}

int8_t cambiarConexionActivaADisco() {
	if (imprimirDebug) {
		printf("--------------------cambiarConexionActivaADisco--------------------\n");
	}

	if (usarPoolConexiones) {
		cerrarTodasLasConexiones();
		memset(IP_ACTIVA, '\0', NI_MAXHOST);
		memcpy(IP_ACTIVA, IP_DISCO, NI_MAXHOST);
		memset(PUERTO_ACTIVO, '\0', 10);
		memcpy(PUERTO_ACTIVO, PUERTO_DISCO, 10);
	} else {
		memset(IP_ACTIVA, '\0', NI_MAXHOST);
		memcpy(IP_ACTIVA, IP_DISCO, NI_MAXHOST);
		memset(PUERTO_ACTIVO, '\0', 10);
		memcpy(PUERTO_ACTIVO, PUERTO_DISCO, 10);
	}
	if (imprimirDebug) {
		printf("--------------------fin-cambiarConexionActivaADisco--------------------\n");
	}
	return 0;
}

int8_t inicializarPoolConexiones() {
	if (imprimirDebug) {
		printf("--------------------inicializarPoolConexiones--------------------\n");
	}
	uint8_t i;
	poolConexiones = (t_conexion*) malloc(MAX_CONEXIONES * sizeof(t_conexion));
	for (i = 0; i < MAX_CONEXIONES; i++)
		poolConexiones[i].enUso = -1;
	if (imprimirDebug) {
		printf("--------------------fin-inicializarPoolConexiones--------------------\n");
	}
	return 0;
}

int8_t hacerPedido(char* envio, uint64_t tamanioEnvio, char* recibo) {
	if (usarPoolConexiones) {
		int8_t error = 0;
		int32_t descriptor;

		error = obtenerConexion(&descriptor);

		if (imprimirDebug) {
			printf("Consegui el descriptor: [%d].\n", descriptor);
		}

		if (!error) {
			if (imprimirDebug) {
				printf("Consegui una conexion disponible.\n");
			}
			int32_t resSend = send(descriptor, envio, tamanioEnvio, 0);
			if (resSend == -1 || errno == EPIPE) {
				if (imprimirDebug) {
					printf("Error en el envio.\n");
				}
				pthread_mutex_lock(&mutexUsandoPoolConexiones);
				cerrarConexion(descriptor);
				pthread_mutex_unlock(&mutexUsandoPoolConexiones);
				return 1;
			} else {
				if (imprimirDebug) {
					printf("Envie: [%d][%d][%d].\n", ((uint8_t) envio[0]), ((uint8_t) envio[1]), ((uint8_t) envio[2]));
				}
				char*buffer = (char*) malloc(MAX_BUFFER);
				memset(buffer, '\0', MAX_BUFFER);
				int32_t resRecv = recv(descriptor, buffer, MAX_BUFFER, 0);
				if (resRecv == -1 || errno == EINTR) {
					if (imprimirDebug) {
						printf("Error en el recibimiento.\n");
					}
					pthread_mutex_lock(&mutexUsandoPoolConexiones);
					cerrarConexion(descriptor);
					pthread_mutex_unlock(&mutexUsandoPoolConexiones);
					return 1;
				} else if (resRecv == 0) {
					printf("Se recibio un mensaje vacio.\n");
					pthread_mutex_lock(&mutexUsandoPoolConexiones);
					habilitarConexion(descriptor);
					pthread_mutex_unlock(&mutexUsandoPoolConexiones);
					return 1;
				} else {
					if (imprimirDebug) {
						printf("resRecv = %d\n", resRecv);
						printf("Recibi: [%d][%d][%d].\n", buffer[0], buffer[1], buffer[2]);
					}
					if (!esPaqueteHandShake(((uint8_t) buffer[0])) && !esPaqueteLectura(((uint8_t) buffer[0])) && !esPaqueteEscritura(((uint8_t) buffer[0])) && !esPaqueteError(((uint8_t) buffer[0]))) {
						memset(buffer, '\0', MAX_BUFFER);
						resRecv = recv(descriptor, buffer, MAX_BUFFER, 0);
					}
					if (resRecv == -1 || errno == EINTR) {
						if (imprimirDebug) {
							printf("Error en el recibimiento.\n");
						}
						pthread_mutex_lock(&mutexUsandoPoolConexiones);
						cerrarConexion(descriptor);
						pthread_mutex_unlock(&mutexUsandoPoolConexiones);
						return 1;
					} else {
						if (imprimirDebug) {
							printf("Recibi: [%d][%d][%d].\n", buffer[0], buffer[1], buffer[2]);
						}
						memset(recibo, '\0', MAX_BUFFER);
						memcpy(recibo, buffer, MAX_BUFFER);

						pthread_mutex_lock(&mutexUsandoPoolConexiones);
						habilitarConexion(descriptor);
						pthread_mutex_unlock(&mutexUsandoPoolConexiones);
						return 0;
					}
				}
			}
		} else {
			return 1;
		}
	} else {
		int8_t error = 0;
		int32_t descriptor;

		error = obtenerConexion(&descriptor);

		if (imprimirDebug) {
			printf("Consegui el descriptor: [%d].\n", descriptor);
		}

		if (!error) {
			if (imprimirDebug) {
				printf("Consegui una conexion disponible.\n");
			}
			int32_t resSend = send(descriptor, envio, tamanioEnvio, 0);
			if (resSend == -1 || errno == EINTR) {
				if (imprimirDebug) {
					printf("Error en el envio.\n");
				}
				cerrarConexion(descriptor);
				return 1;
			} else {
				if (imprimirDebug) {
					printf("Envie: [%d][%d][%d].\n", ((uint8_t) envio[0]), ((uint8_t) envio[1]), ((uint8_t) envio[2]));
				}
				char*buffer = (char*) malloc(MAX_BUFFER);
				memset(buffer, '\0', MAX_BUFFER);
				int32_t resRecv = recv(descriptor, buffer, MAX_BUFFER, 0);
				if (resRecv == -1 || errno == EINTR) {
					if (imprimirDebug) {
						printf("Error en el recibimiento.\n");
					}
					cerrarConexion(descriptor);
					return 1;
				} else if (resRecv == 0) {
					printf("Se recibio un mensaje vacio.\n");
					cerrarConexion(descriptor);
					return 1;
				} else {
					if (imprimirDebug) {
						printf("resRecv = %d\n", resRecv);
						printf("Recibi: [%d][%d][%d].\n", buffer[0], buffer[1], buffer[2]);
					}
					if (!esPaqueteHandShake(((uint8_t) buffer[0])) && !esPaqueteLectura(((uint8_t) buffer[0])) && !esPaqueteEscritura(((uint8_t) buffer[0])) && !esPaqueteError(((uint8_t) buffer[0]))) {
						memset(buffer, '\0', MAX_BUFFER);
						resRecv = recv(descriptor, buffer, MAX_BUFFER, 0);
					}
					if (resRecv == -1 || errno == EINTR) {
						if (imprimirDebug) {
							printf("Error en el recibimiento.\n");
						}
						cerrarConexion(descriptor);
						return 1;
					} else {
						if (imprimirDebug) {
							printf("Recibi: [%d][%d][%d].\n", buffer[0], buffer[1], buffer[2]);
						}
						memset(recibo, '\0', MAX_BUFFER);
						memcpy(recibo, buffer, MAX_BUFFER);

						cerrarConexion(descriptor);
						return 0;
					}
				}
			}
		} else {
			return 1;
		}
	}
}

//--------------------------------------------------
//HANDSHAKE
//--------------------------------------------------

int8_t hacerHandShake(int32_t descriptor) {
	if (imprimirDebug) {
		printf("--------------------hacerHandShake--------------------\n");
	}

	if (usarPoolConexiones) {
		int8_t error = 0;
		int8_t handShakeExitoso = 0;
		int8_t cerreDescriptor = 0;

		while (!handShakeExitoso && !cerreDescriptor) {

			if (imprimirDebug) {
				printf("Intento hacer un handshake.\n");
			}

			t_paquete paquete;
			paquete.type = TIPO_HANDSHAKE;
			paquete.pLength = 0;
			paquete.payLoad = NULL;

			if (imprimirDebug) {
				printf("Arme un paquete con tipo [%d] y pLength [%d].\n", paquete.type, paquete.pLength);
			}

			char* cadenaAEnviar;
			error = desempaquetar(paquete, &cadenaAEnviar);

			if (!error) {

				char* cadenaRecibida = (char*) malloc(MAX_BUFFER);
				int32_t resSend = send(descriptor, cadenaAEnviar, 3, 0);

				if (resSend != -1 && errno != EPIPE) {

					char* cadenaRecibida = (char*) malloc(MAX_BUFFER);

					int32_t resRecv = recv(descriptor, cadenaRecibida, MAX_BUFFER, 0);

					if (resRecv > 0 && errno != EINTR) {

						t_paquete paqueteRecibido;

						error = empaquetar(cadenaRecibida, &paqueteRecibido);

						if (!error) {

							if ((paqueteRecibido.type == 0) && (paqueteRecibido.pLength == 0)) {
								if (imprimirDebug) {
									printf("El handshake fue exitoso.\n");
								}
								return 0;
							} else {
								if (imprimirDebug) {
									printf("El handshake no fue exitoso.\n");
								}
								if (esPaqueteError(paqueteRecibido.type) && (paqueteRecibido.pLength != 0)) {
									if (imprimirDebug) {
										printf("El paquete es de tipo error.\n");
									}
									if (strcmp(paqueteRecibido.payLoad, ERROR_CAMBIAR_CONEXION_A_RAID1) == 0) {
										if (imprimirDebug) {
											printf("Corresponde hacer la conexion con el raid, cambio las conexiones.\n");
										}
										cambiarConexionActivaARaid1();
										close(descriptor);
										cerreDescriptor = 1;

									} else if (strcmp(paqueteRecibido.payLoad, ERROR_CAMBIAR_CONEXION_A_DISCO) == 0) {
										if (imprimirDebug) {
											printf("No debo conectarme al raid, hay un solo disco, cambio las conexiones.\n");
										}
										cambiarConexionActivaADisco();
										close(descriptor);
										cerreDescriptor = 1;

									} else if (strcmp(paqueteRecibido.payLoad, ERROR_NINGUN_DISCO) == 0) {
										if (imprimirDebug) {
											printf("No hay ningun disco.\n");
										}
									} else {
										if (imprimirDebug) {
											printf("No entiendo el mensaje de error.");
										}
									}
								} else {
									//NO ES PAQUETE DE ERROR NI HANDSHAKE
									if (imprimirDebug) {
										printf("Paquete de tipo [%d] no esperado.\n", paqueteRecibido.type);
									}
								}
								handShakeExitoso = 0;
							}
						} else {
							//ERROR AL EMPAQUETAR
							handShakeExitoso = 0;
						}
					} else if (resRecv == 0) {
						if (imprimirDebug) {
							printf("Llego un mensaje vacio.\n");
						}
					} else {
						//ERROR EN EL RECEIVE
						if (imprimirDebug) {
							printf("Error en el receive.\n");
						}
						close(descriptor);
						cerreDescriptor = 1;
					}
				} else {
					//ERROR EN EL SEND
					if (imprimirDebug) {
						printf("Error en el send.\n");
					}
					close(descriptor);
					cerreDescriptor = 1;
				}
				free(cadenaRecibida);
			} else {
				//ERROR AL DESEMPAQUETAR
				handShakeExitoso = 0;
			}
			free(cadenaAEnviar);
			sleep(1);
		}

		if (imprimirDebug) {
			printf("--------------------fin-hacerHandShake--------------------\n");
		}
		if (cerreDescriptor) {
			return -1;
		} else {
			return 0;
		}
	} else {
		int8_t error = 0;
		int8_t handShakeExitoso = 0;
		int8_t cerreDescriptor = 0;

		while (!handShakeExitoso && !cerreDescriptor) {

			if (imprimirDebug) {
				printf("Intento hacer un handshake.\n");
			}

			t_paquete paquete;
			paquete.type = TIPO_HANDSHAKE;
			paquete.pLength = 0;
			paquete.payLoad = NULL;

			if (imprimirDebug) {
				printf("Arme un paquete con tipo [%d] y pLength [%d].\n", paquete.type, paquete.pLength);
			}

			char* cadenaAEnviar;
			error = desempaquetar(paquete, &cadenaAEnviar);

			if (!error) {

				char* cadenaRecibida = (char*) malloc(MAX_BUFFER);
				int32_t resSend = send(descriptor, cadenaAEnviar, 3, 0);

				if (resSend != -1 && errno != EPIPE) {

					char* cadenaRecibida = (char*) malloc(MAX_BUFFER);

					int32_t resRecv = recv(descriptor, cadenaRecibida, MAX_BUFFER, 0);

					if (resRecv > 0 && errno != EINTR) {

						t_paquete paqueteRecibido;

						error = empaquetar(cadenaRecibida, &paqueteRecibido);

						if (!error) {

							if ((paqueteRecibido.type == 0) && (paqueteRecibido.pLength == 0)) {
								if (imprimirDebug) {
									printf("El handshake fue exitoso.\n");
								}
								return 0;
							} else {
								if (imprimirDebug) {
									printf("El handshake no fue exitoso.\n");
								}
								if (esPaqueteError(paqueteRecibido.type) && (paqueteRecibido.pLength != 0)) {
									if (imprimirDebug) {
										printf("El paquete es de tipo error.\n");
									}
									if (strcmp(paqueteRecibido.payLoad, ERROR_CAMBIAR_CONEXION_A_RAID1) == 0) {
										if (imprimirDebug) {
											printf("Corresponde hacer la conexion con el raid, cambio las conexiones.\n");
										}
										cambiarConexionActivaARaid1();
										cerrarConexion(descriptor);
										cerreDescriptor = 1;

									} else if (strcmp(paqueteRecibido.payLoad, ERROR_CAMBIAR_CONEXION_A_DISCO) == 0) {
										if (imprimirDebug) {
											printf("No debo conectarme al raid, hay un solo disco, cambio las conexiones.\n");
										}
										cambiarConexionActivaADisco();
										cerrarConexion(descriptor);
										cerreDescriptor = 1;

									} else if (strcmp(paqueteRecibido.payLoad, ERROR_NINGUN_DISCO) == 0) {
										if (imprimirDebug) {
											printf("No hay ningun disco.\n");
										}
									} else {
										if (imprimirDebug) {
											printf("No entiendo el mensaje de error.");
										}
									}
								} else {
									//NO ES PAQUETE DE ERROR NI HANDSHAKE
									if (imprimirDebug) {
										printf("Paquete de tipo [%d] no esperado.\n", paqueteRecibido.type);
									}
								}
								handShakeExitoso = 0;
							}
						} else {
							//ERROR AL EMPAQUETAR
							handShakeExitoso = 0;
						}
					} else if (resRecv == 0) {
						if (imprimirDebug) {
							printf("Llego un mensaje vacio.\n");
						}
					} else {
						//ERROR EN EL RECEIVE
						if (imprimirDebug) {
							printf("Error en el receive.\n");
						}
						cerrarConexion(descriptor);
						cerreDescriptor = 1;
					}
				} else {
					//ERROR EN EL SEND
					if (imprimirDebug) {
						printf("Error en el send.\n");
					}
					cerrarConexion(descriptor);
					cerreDescriptor = 1;
				}
				free(cadenaRecibida);
			} else {
				//ERROR AL DESEMPAQUETAR
				handShakeExitoso = 0;
			}
			free(cadenaAEnviar);
			sleep(1);
		}

		if (imprimirDebug) {
			printf("--------------------fin-hacerHandShake--------------------\n");
		}
		if (cerreDescriptor) {
			return -1;
		} else {
			return 0;
		}
	}
}
